package com.wxmit.ot.gen.constant;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.wxmit.ot.enums.YesOrNoEnum;
import com.wxmit.ot.gen.annotate.CodeTemplateParamAnn;
import com.wxmit.ot.gen.domain.GenTable;
import com.wxmit.ot.gen.domain.GenTableColumn;

import java.lang.reflect.Field;
import java.util.*;

/**
 * CodeTemplateParamConstant
 *
 * @author huangxiong
 * @version V1.0
 * @date 2023/2/24 11:43
 */
public class CodeTemplateParamConstant {

    public static final String CONSTANT_className = "className";
    public static final String CONSTANT_ClassName = "ClassName";
    private static final String CONSTANT_columns = "columns";
    private static final String CONSTANT__PK_columns = "pkColumn";

    /**
     *  代码模版变量描述map
     */
    public static final Map<String,Object> codeTemplateParamDescribeMap;

    static {
        codeTemplateParamDescribeMap = initCodeTemplateParamDescribeMap();
    }

    /**
     *  根据GenTable对象 构建 参数map
     * @param genTable genTable 对象
     * @return 模版变量参数map
     */
    public static Map<String,Object> buildByGenTable(GenTable genTable){
        Map<String,Object> result = new LinkedHashMap<>();

        Map<String, Field> fieldMap = ReflectUtil.getFieldMap(GenTable.class);
        fieldMap.forEach((key,field)->{
            CodeTemplateParamAnn annotation = field.getAnnotation(CodeTemplateParamAnn.class);
            if(!annotation.isNull()){
                result.put(key,ReflectUtil.getFieldValue(genTable,field));
            }
        });

        processClassName(result);

        if(!CollectionUtil.isEmpty(genTable.getColumns())){
            // 处理主键
            Optional<GenTableColumn> pkColumnOptional = genTable.getColumns().filter(it -> YesOrNoEnum.getBooleanByCode(it.getIsPk())).findFirst();
            pkColumnOptional.ifPresent(column -> processPkColumn(result, column));

            // 处理列数据
            List<Map<String,Object>> columns = genTable.getColumns().map(it->{
                Map<String,Object> columnsFieldRemark = new LinkedHashMap<>();
                Map<String,Field> columnFieldMap = ReflectUtil.getFieldMap(GenTableColumn.class);
                columnFieldMap.forEach((key,field)->{
                    CodeTemplateParamAnn annotation = field.getAnnotation(CodeTemplateParamAnn.class);
                    if(!annotation.isNull()){
                        columnsFieldRemark.put(key,ReflectUtil.getFieldValue(it,field));
                    }
                });
                return columnsFieldRemark;
            }).toList();
            result.put(CONSTANT_columns, columns);
        }
        return result;
    }

    private static Map<String,Object> initCodeTemplateParamDescribeMap(){
        Map<String,Object> result = new LinkedHashMap<>();

        Map<String, Field> fieldMap = ReflectUtil.getFieldMap(GenTable.class);

        fieldMap.forEach((k,v)->doPutValByCodeTemplateParamAnn(k,v,result));

        processClassName(result);
        processPkColumn(result,null);
        Map<String,String> columnsFieldRemark = new LinkedHashMap<>();
        result.put(CONSTANT_columns, ListUtil.toList(columnsFieldRemark));
        fieldMap = ReflectUtil.getFieldMap(GenTableColumn.class);

        fieldMap.forEach((k,v)->doPutValByCodeTemplateParamAnn(k,v,columnsFieldRemark));

        return Collections.unmodifiableMap(result);
    }

    /**
     *  处理主键列（更新到 结果map 中）
     * @param result 结果map
     * @param column 主见列
     */
    private static void processPkColumn(Map<String, Object> result,GenTableColumn column) {
        Map<String,Field> fieldMap = ReflectUtil.getFieldMap(GenTableColumn.class);

        Map<String,Object> pkColumnMap = new LinkedHashMap<>(fieldMap.size());
        if(Objects.isNull(column)){
            fieldMap.forEach((k,v)->doPutValByCodeTemplateParamAnn(k,v,pkColumnMap));
        }else{
            fieldMap.forEach((k,v)->{
                CodeTemplateParamAnn annotation = v.getAnnotation(CodeTemplateParamAnn.class);
                if(!annotation.isNull()){
                    pkColumnMap.put(k,ReflectUtil.getFieldValue(column,v));
                }
            });
        }
        result.put(CONSTANT__PK_columns,pkColumnMap);
    }

    private static void processClassName(Map<String,Object> map){
        // 处理className
        String className = StrUtil.lowerFirst(((String)map.getOrDefault(CONSTANT_className, "")));
        map.set(CONSTANT_className,className);
        map.set(CONSTANT_ClassName,StrUtil.upperFirst(className));
    }

    private static void doPutValByCodeTemplateParamAnn(String key,Field field,Map map){
        CodeTemplateParamAnn annotation = field.getAnnotation(CodeTemplateParamAnn.class);
        if(!annotation.isNull()){
            map.put(key,annotation.value());
        }
    }
}
